home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*----------------------------------------------------------------------
- * $Id: PlayEngine.c,v 2.7 92/07/17 16:43:44 carlson Exp $
- *
- * PlayEngine.c This file contains all the routines for accessing
- * setting up and communicating with the play engine.
- *
- * The purpose of the play engine is to provide a method of running
- * an audio track at a high priority so that it won't be interrupted
- * by normal system activity, including windows being moved around
- * and background system deamon activity.
- *
- * The technique used is to sproc into two processes where one process
- * (the play engine) raises its priority real high and the other process
- * (the application) remains at the user's privilege level. This
- * procedure requires the executable to be owned by root and the set-UID
- * bit to be set.
- *
- * This set of routines will work with or without the use of system
- * semaphores. A #define indicates how it should be compiled.
- *
- * MISCELLANEOUS:
- * Notice that there are no references to 'errno'. These
- * references have been changed to call the function 'oserror'.
- * This is because, when working with multiple processes, the
- * value for errno can be set by either process and this could
- * cause confusing results. Calling 'oserror' guarantees the
- * process of getting "its" last value of 'errno'.
- *
- * As of IRIX 5.1, 'errno' is actually #defined to call
- * 'oserror'. Either way, it is a good idea to read 'oserror'
- * or 'errno' into a local variable and then process its
- * contents rather than keep checking the value in 'errno'.
- *
- * Function Description:
- * This is a short description of each of the functions. For
- * a more complete description, read the documentation preceding
- * each function.
- *
- * Static Functions:
- * -----------------
- * semOp Perform a semaphore operation. Handles
- * situations where signals interrupt the wait
- * or where the parent dies.
- *
- * other_process This is the routine that is referred to in
- * sproc call and is the "main" for the "play
- * engine" process. It contains an "infinite"
- * loop that waits for commands from the parent
- * process.
- *
- * External Functions:
- * -------------------
- * play_engine_thread
- * This is the routine that will be called
- * whenever the 'other_process' receives a
- * "run" command. When it returns, the
- * 'other_process' will go back into a wait
- * to be commanded to start again.
- *
- * Global Functions:
- * -----------------
- * CreateSubProcess
- * This routine actually performs the sproc to
- * create the 'other_process'. It also sets
- * up the semaphore arena and initializes
- * various flags.
- *
- * StartSubProcess Called by the parent process whenever it
- * wants to start the subprocess again. This
- * routine does what is necessary to set/clear
- * semaphores in order to start the 'other_process'.
- *
- * DestroySubProcess
- * This routine *must* be called when the
- * subprocess is no longer needed. It returns
- * the semaphore arena to the system and kills
- * the subprocess. If this is not done, the
- * subprocess doesn't quit (unless special code
- * is set up in the play_engine_thread to
- * find out that the parent has died).
- *
- * Conditional Compilation:
- * The following symbols will perform special compilation:
- *
- * Define on compile command line:
- * -------------------------------
- * USE_SEMAPHORES Compiles process so that it will use semaphores
- * to handshake between the two processes. Other-
- * wise it uses the 'blockproc' functions.
- *
- * DEBUG_SP Add special debug prints and routines to debug
- * the subprocess activities.
- *
- * DEBUG_PRIO Add special debug prints to check priority stuff.
- *
- * Defined in this source file:
- * ----------------------------
- * PARENT_PRI The parent is also set up with non-degrading
- * priority. This symbol should be set to the
- * desired priority.
- *
- * USE_EXT_SEM Use external semaphores rather than our own
- * arena.
- *----------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------
- * III N N CCC L U U DDDD EEEEE SSS
- * I NN N C C L U U D D E S S
- * I NN N C L U U D D E S
- * I N N N C L U U D D EEE SSS
- * I N NN C L U U D D E S
- * I N NN C C L U U D D E S S
- * III N N CCC LLLL UUU DDDD EEEEE SSS
- *----------------------------------------------------------------------*/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <errno.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/prctl.h>
-
- #ifdef USE_SEMAPHORES
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #endif
-
- #include <sys/schedctl.h>
- #include <sys/resource.h>
-
- /*------------------------------------------------------------------------
- * DDDD EEEEE FFFFF III N N EEEEE SSS
- * D D E F I NN N E S S
- * D D E F I NN N E S
- * D D EEE FFF I N N N EEE SSS
- * D D E F I N NN E S
- * D D E F I N NN E S S
- * DDDD EEEEE F III N N EEEEE SSS
- *------------------------------------------------------------------------*/
-
- /* #define PARENT_PRI 32 /* Parent non-degrading priority */
-
- #ifdef USE_SEMAPHORES
- /* #define USE_EXT_SEM /* Set for external semaphore */
-
- #ifdef USE_EXT_SEM
- #define SEM_KEY 37 /* Semaphore key */
- #endif
-
- /*----
- * The following semaphores are defined. Note that there is some
- * redundancy between these semaphores and the static variables 'run'
- * and 'running'.
- *
- * Semaphore Purpose
- * --------- -------
- * SEM_RUN Used to block child process. Child waits for
- * this semaphore to be cleared by the parent to run.
- * Right after being started, the child sets this
- * semaphore to 1 to indicate it has started. It
- * is initially set to 1 by parent before creating
- * the child. It is cleared in StartSubProcess.
- *
- * SEM_RUNNING Used to indicate the state of the child. It
- * is set to 1 by the child just prior to calling
- * play_engine_thread. It is cleared prior to
- * the child blocking and set after the child is
- * unblocked.
- *----*/
-
- #define SEM_RUN 0
- #define SEM_RUNNING 1
- #define NUM_SEMS 4 /* Number of semaphores to get */
-
- #define S_UREAD 00400
- #define S_UALTER 00200
- #define S_GREAD 00040
- #define S_GALTER 00020
- #define S_OREAD 00004
- #define S_OALTER 00002
- #endif
-
- /*------------------------------------------------------------------------
- * PPPP RRRR OOO TTTTT OOO TTTTT Y Y PPPP EEEEE SSS
- * P P R R O O T O O T Y Y P P E S S
- * P P R R O O T O O T Y Y P P E S
- * PPPP RRRR O O T O O T Y PPPP EEE SSS
- * P R R O O T O O T Y P E S
- * P R R O O T O O T Y P E S S
- * P R R OOO T OOO T Y P EEEEE SSS
- *------------------------------------------------------------------------*/
-
- extern void play_engine_thread (void);
-
- /*------------------------------------------------------------------------
- * EEEEE X X TTTTT EEEEE RRRR N N AAA L SSS
- * E X X T E R R NN N A A L S S
- * E X X T E R R NN N A A L S
- * EEE X T EEE RRRR N N N AAAAA L SSS
- * E X X T E R R N NN A A L S
- * E X X T E R R N NN A A L S S
- * EEEEE X X T EEEEE R R N N A A LLLLL SSS
- *------------------------------------------------------------------------*/
-
- extern int ndPriority;
- extern int ProcessPriority;
- extern int PGPriority;
- extern int UserPriority;
-
- /*------------------------------------------------------------------------
- * L OOO CCC AAA L SSS
- * L O O C C A A L S S
- * L O O C A A L S
- * L O O C AAAAA L SSS
- * L O O C A A L S
- * L O O C C A A L S S
- * LLLLL OOO CCC A A LLLLL SSS
- *------------------------------------------------------------------------*/
-
- #ifdef USE_SEMAPHORES
- static key_t semKey;
- static int semaphoreID;
- static union semun semArg;
- static struct semid_ds semBuf[NUM_SEMS];
- static ushort semArray[NUM_SEMS];
- static struct sembuf semBuffs[NUM_SEMS];
- #endif
-
- static pid_t parentPID;
- static pid_t childPID;
-
- /*---
- * run Set by parent when subprocess is to run. Cleared by
- * child when it is acknowledged and before running.
- * running Initially set by parent before creating subprocess.
- * Indicates state of child. Cleared before child
- * blocks. Set when child unblocks.
- * priviledged Set if we had priviledges when we started.
- *----*/
-
- static int run;
- static int running;
-
- static int priviledged;
-
- #if defined(USE_SEMAPHORES) && defined(DEBUG_SP)
- /*----------------------------------------------------------------------
- * ReadBuf Read the semaphore buffer.
- *----------------------------------------------------------------------*/
-
- struct semid_ds *ReadBuf (void)
- {
- static char *funcname = "ReadBuf";
-
- union semun arg;
- static struct semid_ds buf;
-
- arg.buf = &buf;
- if (semctl (semaphoreID, 0, IPC_STAT, arg) < 0) {
- fprintf (stderr, "%s: Problem reading the semaphore buffer.\n",
- funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
-
- return &buf;
- }
-
- /*----------------------------------------------------------------------
- * ReadSem Read a semaphore value.
- *----------------------------------------------------------------------*/
-
- ushort ReadSem (int sem)
- {
- static char *funcname = "ReadSem";
-
- register ushort val;
-
- if ((val = semctl (semaphoreID, sem, GETVAL)) < 0) {
- fprintf (stderr, "%s: Problem reading semaphore value.\n", funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
-
- return val;
- }
-
- /*----------------------------------------------------------------------
- * ReadSemPID Read a semaphore value.
- *----------------------------------------------------------------------*/
-
- short ReadSemPID (int sem)
- {
- static char *funcname = "ReadSemPID";
-
- register short val;
-
- if ((val = semctl (semaphoreID, sem, GETPID)) < 0) {
- fprintf (stderr, "%s: Problem reading semaphore PID.\n", funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
-
- return val;
- }
-
- /*----------------------------------------------------------------------
- * ReadSemncnt Read a semaphore value.
- *----------------------------------------------------------------------*/
-
- short ReadSemncnt (int sem)
- {
- static char *funcname = "ReadSemncnt";
-
- register short val;
-
- if ((val = semctl (semaphoreID, sem, GETNCNT)) < 0) {
- fprintf (stderr, "%s: Problem reading semaphore Ncnt.\n", funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
-
- return val;
- }
-
- /*----------------------------------------------------------------------
- * ReadSemzcnt Read a semaphore value.
- *----------------------------------------------------------------------*/
-
- short ReadSemzcnt (int sem)
- {
- static char *funcname = "ReadSemzcnt";
-
- register short val;
-
- if ((val = semctl (semaphoreID, sem, GETZCNT)) < 0) {
- fprintf (stderr, "%s: Problem reading semaphore Zcnt.\n", funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
-
- return val;
- }
- #endif
-
- #ifdef USE_SEMAPHORES
- /*----------------------------------------------------------------------
- * semOp Perform a semaphore operation and wait.
- *
- * Description:
- * Takes as input the 'sembuf' structure array, as is normally
- * passed to the system function 'semop'
- *----------------------------------------------------------------------*/
-
- static void semOp (struct sembuf *sembufs, int nbufs)
- {
- static char *funcname = "semOp";
- register int errno = -1;
-
- while (errno) {
- errno = 0;
- if (semop (semaphoreID, sembufs, nbufs) < 0) {
- errno = oserror ();
-
- fprintf (stderr, "%s: semop error.\n", funcname);
- fprintf (stderr, " %s\n", strerror (errno));
- if (errno == EIDRM) { /* Semaphores are gone */
- exit (0);
- }
- }
- }
- }
- #endif
-
- /*----------------------------------------------------------------------
- * other_process Other process that will be run.
- *----------------------------------------------------------------------*/
-
- static void other_process (void *x)
- {
- static char *funcname = "other_process";
- register uid_t uid;
- register int i;
- #ifdef USE_SEMAPHORES
- struct sembuf semBuffs[NUM_SEMS];
- #endif
-
- childPID = getpid ();
-
- #ifdef DEBUG_SP
- fprintf (stderr, "%s: running with PID %d\n", funcname, childPID);
- #endif
-
- /*----
- * Initialize all of our semaphore buffers to have the
- * semaphore ID in them. We need our own copy so we don't
- * screw up the parent process.
- *----*/
-
- for (i = 0; i < NUM_SEMS; i++)
- {
- semBuffs[i].sem_num = i;
- semBuffs[i].sem_flg = 0;
- }
-
- /*----
- * If we are running with priveleges, take advantage of it.
- *----*/
-
- if (geteuid () == 0) {
- priviledged = 1;
-
- /*----
- * Set up non-degrading priorities to the max.
- *----*/
-
- if (schedctl (NDPRI, 0, ndPriority) < 0) {
- fprintf (stderr, "%s: Unable to set non-degrading priority.\n",
- funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
- else if (schedctl (SLICE, 0, CLK_TCK) < 0)
- {
- fprintf (stderr, "%s: Unable to set time slice.\n", funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
-
- /*----
- * Force this process to remain resident in memory at all times.
- *----*/
-
- if (prctl (PR_RESIDENT) < 0) {
- fprintf (stderr, "%s: Unable to force residency.\n", funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
-
- /*----
- * Set the process priority as high as possible.
- *----*/
-
- if (setpriority (PRIO_PROCESS, 0, ProcessPriority) < 0) {
- fprintf (stderr, "%s: Unable to set process priority.\n",
- funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
-
- /*----
- * Set the process group priority as high as possible.
- *----*/
-
- if (setpriority (PRIO_PGRP, 0, PGPriority) < 0) {
- fprintf (stderr, "%s: Unable to set process group priority.\n",
- funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
-
- /*----
- * Set the user priority as high as possible.
- *----*/
-
- if (setpriority (PRIO_USER, 0, UserPriority) < 0) {
- fprintf (stderr, "%s: Unable to set user priority.\n",
- funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
- }
-
- /*----
- * Since we are done with the privileged stuff, lower our
- * privilege back to the user's privilege. We don't want
- * to mess something up by mistake.
- *----*/
-
- uid = getuid ();
- if (setreuid (uid, uid) < 0) {
- fprintf (stderr, "%s: Unable to set UIDs.\n", funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
-
- #ifdef DEBUG_PRIO
- fprintf (stderr, "%s: Running with the following priorities:\n",
- funcname);
- fprintf (stderr, "\tPRIO_PROCESS %d\n",
- getpriority (PRIO_PROCESS, 0));
- fprintf (stderr, "\tPRIO_PGRP %d\n",
- getpriority (PRIO_PGRP, 0));
- fprintf (stderr, "\tPRIO_USER %d\n",
- getpriority (PRIO_USER, 0));
- #endif
-
- /*====
- * Top of subprocess loop
- *====*/
-
- while (1) {
-
- #ifdef DEBUG_SP
- fprintf (stderr, "%s: Waiting for RUN\n", funcname);
- #endif
-
-
- /*----
- * Set our state to not running.
- *----*/
-
- running = 0;
-
- /*----
- * Wait for semaphore flag to become 0 to continue.
- * Decrement the semaphore indicating we are running.
- *----*/
-
- #ifdef USE_SEMAPHORES
- semBuffs[SEM_RUNNING].sem_op = -1; /* Clear running */
- semOp (&semBuffs[SEM_RUNNING], 1);
- semBuffs[SEM_RUN].sem_op = 0; /* Wait for semaphore */
- semOp (&semBuffs[SEM_RUN], 1);
- #else
- if (blockproc (childPID) < 0) {
- fprintf (stderr, "%s: An error occurred blocking myself.\n",
- funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- exit (-1);
- }
- #endif
-
- /*----
- * Set our state to running.
- * Clear the request to run.
- * Increment the semaphore requesting us to run.
- * Increment the semaphore indicating we are running.
- *----*/
-
- #ifdef USE_SEMAPHORES
- semBuffs[SEM_RUN].sem_op = 1;
- semBuffs[SEM_RUNNING].sem_op = 1;
- semOp (&semBuffs[SEM_RUN], 2);
- #endif
-
- running = 1;
- run = 0;
-
- #ifdef DEBUG_SP
- fprintf (stderr, "%s: Ok, I'm running.\n", funcname);
- #endif
-
- /*----
- * Execute the play engine.
- *----*/
-
- play_engine_thread ();
- }
- }
-
- /*------------------------------------------------------------------------
- * WaitForSubProcess Waits for subprocess to complete.
- *------------------------------------------------------------------------*/
-
- void WaitForSubProcess (void)
- {
- static char *funcname = "WaitForSubProcess";
-
- #ifdef DEBUG_SP
- fprintf (stderr, "%s: Waiting for child to stop running.\n", funcname);
- #endif
-
- while (running && !run) /* If flag is set, then we */
- sginap (1); /* shouldn't even check. */
-
- #ifdef USE_SEMAPHORES
- semBuffs[SEM_RUNNING].sem_op = 0; /* Ok, now check if running */
- semOp (&semBuffs[SEM_RUNNING], 1);
- #endif
- }
-
- /*----------------------------------------------------------------------
- * CreateSubProcess Routine creates the subprocess and semaphores.
- *----------------------------------------------------------------------*/
-
- void CreateSubProcess (void)
- {
- static char *funcname = "CreateSubProcess";
-
- register uid_t uid;
- register int i;
-
- /*----
- * First step is to create a semaphore for us to use between
- * processes.
- * 1. Use ftok to key a key identifier to use.
- * 2. Use semget to get a block of semaphores.
- *----*/
-
- #ifdef USE_SEMAPHORES
- #ifdef USE_EXT_SEM
- semKey = ftok ("/usr", SEM_KEY);
- semaphoreID = semget (semKey, NUM_SEMS, (IPC_CREAT |
- S_UREAD | S_UALTER | S_GREAD |
- S_GALTER));
- #else
- semaphoreID = semget (IPC_PRIVATE, NUM_SEMS,
- (S_UREAD | S_UALTER | S_GREAD | S_GALTER));
- #endif
- if (semaphoreID < 0) {
- fprintf (stderr, "%s: Unable to get semaphore ID.\n", funcname);
- fprintf (stderr, " %s\n", strerror (errno));
- exit (0);
- }
-
- /*----
- * Be sure to make the owner of this semaphore the real UID.
- *----*/
-
- uid = getuid ();
- semArg.buf = semBuf;
- if (semctl (semaphoreID, -1, IPC_STAT, semArg) < 0)
- {
- fprintf (stderr, "%s: Unable to get semaphore buffers.\n", funcname);
- fprintf (stderr, " %s\n", strerror (errno));
- }
- else
- {
- for (i = 0; i < NUM_SEMS; i++)
- semBuf[i].sem_perm.uid = uid;
- if (semctl (semaphoreID, -1, IPC_SET, semArg) < 0)
- {
- fprintf (stderr, "%s: Unable to set semaphore UIDs.\n", funcname);
- fprintf (stderr, " %s\n", strerror (errno));
- }
- }
-
- #ifdef DEBUG_SP
- fprintf (stderr, "%s: Received semaphore ID %d.\n", funcname, semaphoreID);
- #endif
-
- /*----
- * Next, clear the semaphores.
- *----*/
-
- memset (semArray, 0, sizeof (semArray));
- semArg.array = semArray;
- if (semctl (semaphoreID, -1, SETALL, semArg) < 0) {
- fprintf (stderr, "%s: Unable to clear semaphores.\n", funcname);
- fprintf (stderr, " %s\n", strerror (errno));
- exit (-1);
- }
-
- /*----
- * Initialize all of our semaphore buffers to have the
- * semaphore ID in them.
- *----*/
-
- for (i = 0; i < NUM_SEMS; i++)
- {
- semBuffs[i].sem_num = i;
- semBuffs[i].sem_flg = 0;
- }
-
- /*----
- * Set the SEM_RUN semaphore to indicate that we DO NOT
- * want the subprocess to run.
- *----*/
-
- semBuffs[SEM_RUN].sem_op = 1; /* Set to indicate "don't run" */
- semBuffs[SEM_RUNNING].sem_op = 1; /* Assume child is running */
- semOp (&semBuffs[SEM_RUN], 2);
- #endif
-
- run = 0; /* Flag says don't run */
- running = 1; /* Assume child is running */
-
- parentPID = getpid ();
-
- if (sproc (other_process, PR_SALL) < 0) {
- fprintf (stderr, "%s: Unable to sproc other process.\n", funcname);
- fprintf (stderr, " %s\n", strerror (errno));
- exit (-1);
- }
-
- #ifdef PARENT_PRI
- /*----
- * If we are running with priveleges, schedule the non-degrading
- * priority so we are higher than window functions.
- *----*/
-
- if (geteuid () == 0) {
- if (schedctl (NDPRI, 0, PARENT_PRI) < 0) {
- fprintf (stderr, "%s: Unable to set non-degrading priority.\n",
- funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
- }
- #endif
-
- if (setreuid (uid, uid) < 0) {
- fprintf (stderr, "%s: Unable to set UIDs.\n", funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
-
- /*----
- * Wait for child to block
- *----*/
-
- WaitForSubProcess ();
- }
-
- /*----------------------------------------------------------------------
- * DestroySubProcess Kills the subprocess and releases the
- * semaphores.
- *----------------------------------------------------------------------*/
-
- void DestroySubProcess (void)
- {
- static char *funcname = "DestroySubProcess";
-
- if (kill (childPID, SIGKILL) < 0) {
- fprintf (stderr, "%s: Unable to kill child process.\n", funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- }
-
- #ifdef USE_SEMAPHORES
- if (semctl (semaphoreID, 0, IPC_RMID) < 0) {
- fprintf (stderr, "%s: Unable to release semaphores.\n", funcname);
- fprintf (stderr, " %s\n", strerror (errno));
- }
- #endif
- }
-
- /*----------------------------------------------------------------------
- * StartSubProcess Routine for telling the subprocess that it is
- * to do something.
- *----------------------------------------------------------------------*/
-
- void StartSubProcess (void)
- {
- static char *funcname = "StartSubProcess";
- #ifdef USE_SEMAPHORES
- register ushort semval;
- #else
- register int errorNo;
- #endif
-
- /*----
- * Check if child process is already running. Error is so.
- *----*/
-
- #ifdef USE_SEMAPHORES
- if ((semval = semctl (semaphoreID, SEM_RUNNING, GETVAL)) < 0) {
- fprintf (stderr, "%s: Error getting SEM_RUNNING semaphore.\n",
- funcname);
- fprintf (stderr, " %s\n", strerror (oserror ()));
- DestroySubProcess ();
- exit (-1);
- }
- if (semval || running) {
- fprintf (stderr, "%s: Subprocess is still running.\n", funcname);
- fprintf (stderr, " semval = %d, running = %d\n", semval, running);
- DestroySubProcess ();
- exit (-1);
- }
- #else
- if (running)
- {
- fprintf (stderr, "%s: Subprocess is still running.\n", funcname);
- DestroySubProcess ();
- exit (-1);
- }
- #endif
-
- /*----
- * Set the flag indicating we want him to run.
- * Decrement the semaphore to start the play engine.
- * Then send it a signal to kick it.
- *----*/
-
- run = 1;
-
- #ifdef DEBUG_SP
- fprintf (stderr, "%s: Starting subprocess.\n", funcname);
- #endif
-
- #ifdef USE_SEMAPHORES
- semBuffs[SEM_RUN].sem_op = -1;
- semOp (&semBuffs[SEM_RUN], 1);
- #else
- #ifdef DEBUG_SP
- fprintf (stderr, "%s: Unblocking process %d\n", funcname, childPID);
- #endif
-
- if (unblockproc (childPID) < 0) {
- errorNo = oserror ();
- if (errorNo == ESRCH) {
- fprintf (stderr, "%s: The play engine has died for some reason.\n",
- funcname);
- fprintf (stderr, " No further playing or recording can take\n");
- fprintf (stderr, " place. It is recommended that you save\n");
- fprintf (stderr, " your work and exit. You can restart and\n");
- fprintf (stderr, " try again.\n");
- } else {
- fprintf (stderr, "%s: Some kind of error occurred trying to\n",
- funcname);
- fprintf (stderr, " restart the play engine.\n");
- fprintf (stderr, " %s\n", sys_errlist[errorNo]);
- }
- }
-
- #ifdef DEBUG_SP
- if (prctl (PR_ISBLOCKED, childPID))
- fprintf (stderr, "%s: The child %d is still blocked.\n", funcname,
- childPID);
- else
- fprintf (stderr, "%s: The child %d is unblocked.\n", funcname,
- childPID);
- #endif
- #endif
-
- /*----
- * Give the child a moment to get going.
- *----*/
-
- sginap (1);
- }
-